package java

import (
	"fmt"
	"math"
	"unsafe"

	"gitee.com/microwww/jvm-go/jvm/class"
)

// 使用 slot 不使用 interface{}, 可读性更好

type Slot struct {
	Num int32
	Ref *class.Object
}

type Stack struct { // 每次计算结果都是多个入栈或出栈的操作 , 直接使用数组 方便, top 栈顶
	top int32
	val []Slot
}

func (s *Stack) String() string {
	return fmt.Sprintf("TOP: %d, %v", s.top, s.val)
}

////////////// type Stack struct { // 直接使用数组 方便, top 栈顶

func NewStack(max uint16) *Stack {
	if max > 0 {
		return &Stack{
			val: make([]Slot, max),
		}
	}
	return nil
}

func (s *Stack) PopInt() int32 {
	s.top--
	v := s.val[s.top]
	s.val[s.top] = Slot{}
	return v.Num
}

func (s *Stack) PushInt(v int32) {
	s.val[s.top].Num = v
	s.top++
}

func (s *Stack) PopFloat() float32 {
	v := s.PopInt()
	return math.Float32frombits(uint32(v))
}

func (s *Stack) PushFloat(v float32) {
	s.PushInt(int32(math.Float32bits(v)))
}

func (s *Stack) PopDouble() float64 {
	v := s.PopLong()
	return math.Float64frombits(uint64(v))
}

func (s *Stack) PushDouble(v float64) {
	f := math.Float64bits(v)
	s.PushLong(int64(f))
}

func (s *Stack) PopLong() int64 {
	s.top -= 2
	v := int2long(s.val[s.top].Num, s.val[s.top+1].Num)
	return v
}

func (s *Stack) PushLong(v int64) {
	low, height := long2int(v)
	s.val[s.top].Num = low
	s.val[s.top+1].Num = height
	s.top += 2
}

func (v *Stack) PushRef(obj *class.Object) {
	v.val[v.top] = Slot{
		Num: int32(uintptr(unsafe.Pointer(obj))),
		Ref: obj,
	}
	v.top++
}

func (v *Stack) PopRef() *class.Object {
	v.top--
	return v.val[v.top].Ref
}

func (v *Stack) GetRef(indexFromTop int32) *class.Object {
	return v.val[v.top-1-indexFromTop].Ref
}

func (v *Stack) PushSlot(s Slot) {
	v.val[v.top] = s
	v.top++
}

func (v *Stack) PopSlot() Slot {
	v.top--
	return v.val[v.top]
}

func long2int(v int64) (int32, int32) {
	return int32(v), int32(v >> 32)
}

func int2long(low, height int32) int64 {
	v2 := uint32(low)
	v1 := uint32(height)
	return int64(v1)<<32 | int64(v2)
}
